package com.augurit.common.workdayholiday.service.impl;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Map;

import org.jbpm.api.ProcessEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.augurit.common.util.lang.DateUtils;
import com.augurit.common.workdayholiday.model.Time;
import com.augurit.common.workdayholiday.model.TimeSpan;
import com.augurit.common.workdayholiday.service.IWhRegularWorkTimeService;
import com.augurit.common.workdayholiday.service.IWhSpecialTimeService;
import com.augurit.common.workdayholiday.service.IWorkdayHolidayService;
import com.augurit.gzcgwsp.commonex.util.lang.DateUtilsEX;

@Service
@Transactional
public class WorkdayHolidayServiceImpl implements IWorkdayHolidayService {

	@Autowired
	private IWhRegularWorkTimeService whRegularWorkTimeService;
	
	@Autowired
	private IWhSpecialTimeService whSpecialTimeServie;
	
	@Autowired
	private ProcessEngine processEngine;
	
	private final Calendar calendar = new GregorianCalendar();

	/**
	 * 判断某一天是否为假期（包括常规假期或非常规假期）
	 * @param day 某一天
	 * @return
	 */
	public boolean isHoliday(final Date day) {
		if(isRegularHoliday(day) && !isCustomWorkday(day))
			return true;
		if(!isRegularHoliday(day) && isCustomHoliday(day))
			return true;
		return false;	
	}
	
	/**
	 * 判断某一天是否为工作日（包括常规工作日或非常规工作日）
	 * @param day 
	 * @return
	 */
	public boolean isWorkday(final Date day){
		return !isHoliday(day);
	}
	
	/**
	 * 计算某一天经过n个工作日的工作日是哪一天
	 * @param day
	 * @param numOfWorkDays
	 * @return
	 */
	public Date calWorkdayFrom(final Date day, int numOfWorkDays){
		Date thisDay = day;
		for(int i = 0; i < numOfWorkDays; i++){
			//如果这一天是假期，往后推到从这一天开始的第一个工作日
			if(isHoliday(thisDay)){
				thisDay = nextWorkday(thisDay);
			}
			thisDay = nextDay(thisDay);
		}
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}
	
	/**
	 * 计算某一天的工作日时长（多少个小时、多少分钟）
	 * @param day
	 * @return
	 */
	public TimeSpan getTimeSpan(final Date day){
		if(isWorkday(day)){
			//暂时没有考虑，自定义的工作日中的时间长度与常规工作日时间长度不一样
			Map<Integer, TimeSpan> TimeSpans = whRegularWorkTimeService.getReguarWorkTimeSpan();
			//获取当前天的工作时长
			calendar.setTime(day);
			int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
			//表示多少个小时多少分钟
			return TimeSpans.get(dayOfWeek);
		}
		return new TimeSpan(0,0);
	}
	
	public void rollToAmStartTime(final Date day){
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		//表示几点几分
		Time time = whRegularWorkTimeService.getAmStartTime(dayOfWeek);
		//设置为上午上班起始时间
		calendar.setTime(day);
		calendar.set(Calendar.HOUR_OF_DAY, time.getHour());
		calendar.set(Calendar.MINUTE, time.getMinute());
	}
	
	public void rollToPmStartTime(final Date day){
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		//表示几点几分
		Time time = whRegularWorkTimeService.getPmStartTime(dayOfWeek);
		//设置为下午上班起始时间
		calendar.setTime(day);
		calendar.set(Calendar.HOUR_OF_DAY, time.getHour());
		calendar.set(Calendar.MINUTE, time.getMinute());
	}
	
	/**
	 * 是否在某一天的上午工作时间内
	 * @param day
	 * @return
	 */
	public boolean isInAmWorkTime(final Date day, int hour, int minute){
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		//表示几点几分
		Time amEndTime = whRegularWorkTimeService.getAmEndTime(dayOfWeek);
		Time amStartTime = whRegularWorkTimeService.getAmStartTime(dayOfWeek);
		
		Time curTime = new Time(hour, minute);
		return (curTime.compareTo(amStartTime) >= 0 && curTime.compareTo(amEndTime) <=0);
}
	
	/**
	 * 是否在某一天的上午工作时间内
	 * @param day
	 * @return
	 */
	public boolean isInPmWorkTime(final Date day, int hour, int minute){
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		//表示几点几分
		Time pmEndTime = whRegularWorkTimeService.getPmEndTime(dayOfWeek);
		Time pmStartTime = whRegularWorkTimeService.getPmStartTime(dayOfWeek);
		
		Time curTime = new Time(hour, minute);
		return (curTime.compareTo(pmStartTime) >= 0 && curTime.compareTo(pmEndTime) <=0);
	}
	
	public boolean isInRegularWorkTime(final Date day, int hour, int minute){
		if(isInAmWorkTime(day, hour, minute) || isInPmWorkTime(day, hour,minute))
			return true;
		return false;
	}
	
	/**
	 * 计算某一天的某一时刻经过多少工作小时、工作分钟后是哪一个工作日的工作小时、分钟
	 * @param day
	 * @param hours
	 * @param minutes
	 * @return
	 */
	public Date calWorkdayFrom(final Date day, int hours, int minutes){
		Date thisDay = day;
		//如果是假期，往后推到某一个工作日开始
		if(isHoliday(thisDay)){
			thisDay = nextWorkday(thisDay);
			rollToAmStartTime(thisDay);
		}
		
		//剩下时间长度：多少小时、分钟
		TimeSpan remainingTimeSpan = new TimeSpan(hours, minutes);
		//当前日期的工作日时间长度
		TimeSpan curDayTimeSpan = getTimeSpan(thisDay);
		
		while(remainingTimeSpan.compareTo(curDayTimeSpan) > 0){
			remainingTimeSpan = remainingTimeSpan.substract(curDayTimeSpan);
			thisDay = nextDay(thisDay);
			curDayTimeSpan = getTimeSpan(thisDay);
		}
		
		//设置为上班起始时间
		if(!isInRegularWorkTime(thisDay, calendar.get(Calendar.HOUR_OF_DAY),calendar.get(Calendar.MINUTE)))
			rollToAmStartTime(thisDay);
		
		calendar.add(Calendar.HOUR_OF_DAY,remainingTimeSpan.getHours());
		calendar.add(Calendar.MINUTE, remainingTimeSpan.getMinutes());
		
		if(!isInAmWorkTime(thisDay, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE))){
			//表示几点几分
			Time curTime = new Time(calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE));
			Time amEndTime = new Time(12, 0);
			//表示多少个小时多少分钟
			TimeSpan timeSpan = TimeSpan.calTimeSpan(curTime, amEndTime);
			
			rollToPmStartTime(thisDay);
			calendar.add(Calendar.HOUR_OF_DAY, timeSpan.getHours());
			calendar.add(Calendar.MINUTE, timeSpan.getMinutes());
		}
		System.out.println(calendar.getTime());
		return calendar.getTime();
	}
	
	/**
	 * 计算某一天的后一天
	 * @param day
	 * @return
	 */
	public Date nextDay(final Date day){
		calendar.setTime(day);
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}
	
	/**
	 * 计算某一天的前一天
	 * @param day
	 * @return
	 */
	public Date previousDay(final Date day){
		calendar.setTime(day);
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}
	
	/**
	 * 计算从某一天开始向后的第一个工作日
	 * @param day
	 * @return
	 */
	public Date nextWorkday(final Date day){
		Date thisDay = day;
		do{
			thisDay = nextDay(thisDay);
		}while(isHoliday(thisDay));
		return thisDay;
	}
	
	/**
	 * 计算从某一天开始向前的第一个工作日
	 * @param day
	 * @return
	 */
	public Date previousWorkday(final Date day){
		Date thisDay = day;
		do{
			thisDay = previousDay(thisDay);
		}while(isHoliday(thisDay));
		return thisDay;
	}
	
	/**
	 * 计算给定起始日期、结束日期,求其工作日的天数(结束日期)
	 *@param from 起始日期
	 *@param to 结束日期
	 */
	public int calNumOfWorkDays(final Date from, final Date to){
		calendar.setTime(from);
		Date day = from;
		int i = 0;
		while(day.compareTo(to) <= 0){
			if(isWorkday(day))
				i++;
			day = nextDay(day);
		}
		return i;
	}
	
	/**
	 * 计算给定起始日期、结束日期,求其工作日的天数(包括结束日期)，精确到半天
	 * @param from 起始日期
	 * @param to 结束日期
	 * @return 工作日的天数
	 */
	public float calNumOfWorkDaysExactlyHalfOfTheDay(final Date from, final Date to){
		float dayCount = calNumOfWorkDays(from,to);
		
		Calendar endCalendar = Calendar.getInstance();
		endCalendar.setTime(to);
		
		//获取一周中某一天的上午工作结束时间
		Time time = whRegularWorkTimeService.getPmEndTime(2);
		
		if(endCalendar.get(Calendar.HOUR_OF_DAY) <= time.getHour())
			dayCount = dayCount - 0.5f;
		
		return dayCount;
	}
	
	/**
	 * 是否为常规工作日，指周内
	 * @param day
	 * @return
	 */
	public boolean isReguarWorkday(Date day){
		calendar.setTime(day);
		String dayOfWeek = String.valueOf(calendar.get(Calendar.DAY_OF_WEEK));
		List<String> workdays = whRegularWorkTimeService.getRegularWorkdays();
		return workdays.contains(dayOfWeek);
	}
	
	/**
	 * 是否为常规休闲日，指周末
	 * @param day
	 * @return
	 */
	public boolean isRegularHoliday(Date day){
		return !isReguarWorkday(day);
	}
	
	/**
	 * 是否为自定义假期
	 * @param day
	 * @return
	 */
	public boolean isCustomHoliday(Date day){
		String sdfDay = DateUtils.dateTimeToString(day, "dd/MM/yyyy");
		List<String> customHolidays = whSpecialTimeServie.getCustomHolidays();
		return customHolidays.contains(sdfDay);
	}
	
	/**
	 * 是否为自定义工作日
	 * @param day
	 * @return
	 */
	public boolean isCustomWorkday(Date day){
		String sdfDay = DateUtils.dateTimeToString(day, "yyyy-MM-dd");
		List<String> customWorkday = whSpecialTimeServie.getCustomWorkdays();
		List<String> customWorkdays=new ArrayList<String>();
		for(String daystr:customWorkday){
			try {
				//daystr=daystr.replace("/", "-");
				Date newDate= DateUtilsEX.dateFormate(daystr,"dd/MM/yyyy");
				String newDay=DateUtils.dateTimeToString(newDate,  "yyyy-MM-dd");
				customWorkdays.add(newDay);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		boolean flag=customWorkdays.contains(sdfDay);
		return flag;
	}
	
	
	/**
	 * 当前年某一月的第一天
	 * @param month
	 * @return
	 */
	public Date firstDayInMonth(int month){
		assert(month >=0 && month <= 11);
		calendar.set(calendar.get(Calendar.YEAR), month, 1);
		return calendar.getTime();
	}
	/**
	 * 计算指定月的第一个工作日是哪一天
	 * @param month
	 * @return
	 */
	public Date calFirstWorkdayInMonth(int month){
		assert(month >=0 && month <= 11);
		return nextWorkday(firstDayInMonth(month));
	}
	
	/**
	 * 计算当前年指定月的最后一天是哪一天
	 * @param month
	 * @return
	 */
	public Date lastDayInMonth(int month){
		assert(month >=0 && month <= 11);
		int nextMonth = (month + 1) % 12;
		Date fistDayInNextMonth = firstDayInMonth(nextMonth);
		
		calendar.setTime(fistDayInNextMonth);
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		
		return calendar.getTime();
	}
	/**
	 * 计算当前年指定月的最后一个工作日是哪一天
	 * @param month
	 * @return
	 */
	public Date calLastWorkdayInMonth(int month){
		assert(month >=0 && month <= 11);
		return previousWorkday(lastDayInMonth(month));
	}
	
	/**
	 * 计算当前年指定月的工作日的天数
	 * @param month
	 * @return
	 */
	public int calNumOfWorkDaysInMonth(int month){
		assert(month >=0 && month <= 11);
		Date fisrtDayInMonth = firstDayInMonth(month);
		Date lastDayInMonth = lastDayInMonth(month);
		return calNumOfWorkDays(fisrtDayInMonth, lastDayInMonth);
	}

	/**
	 * 计算开始日期经过几个工作日后的日期
	 * @param startDate 开始时间
	 * @param durationExpression 结束时间的表达式，例如是"6 business days"
	 * @return 开始日期经过几个工作日后的日期
	 */
    public Date calculateDueDate(Date startDate,String durationExpression){
//    	Date endDate = Duration.calculateDueDate(startDate, durationExpression);
    	Date endDate = processEngine.getExecutionService().calculateDueDate(startDate, durationExpression);
    	
    	return endDate;
    }

    /*
     * (non-Javadoc)
     * @see com.augurit.common.workdayholiday.service.IWorkdayHolidayService#getWorkDays(java.util.Date, java.util.Date)
     */
	@Override
	public int getWorkDays(Date startDate, Date endDate) {
		calendar.setTime(startDate);
		Date day = startDate;
		int i = 0;
		while(day.compareTo(endDate) <= 0){
			if(isWorkdays(day))
				i++;
			day = this.nextDay(day);
		}
		return i;
		
	}
	
	/**
	 * 判断某一天是不是工作日
	 */
	public boolean isWorkdays(final Date day) {
		boolean weekday=isRegularHoliday(day); 
		boolean workday=isCustomWorkday(day);
		boolean holiday=isCustomHoliday(day);
		if(holiday){//如果是自定义假期直接为不是工作日
			return false;
		}
		if(workday && weekday){//如果是自定义工作日 又是周末
			return true;
		}if(weekday && !holiday){//如果是周末并且又不是自定义假期
			return false;
		}
			return true;	
		
	}
	
}
